﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.ServiceModel.DomainServices.Client;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using QSHC.LibrarySL.Extension;
using QSHC.LibrarySL.MVVM;
using QSHC.LibrarySL.Ria;
using QSHC.QSchedule.Web.Models;
using QSHC.QSchedule.Web.Services;
using QSHC.QSchedule.Silverlight.Helpers;
using QSHC.QSchedule.Silverlight.Models;
using QSHC.QSchedule.Silverlight.PatientDataService;
using QSHC.QSchedule.Silverlight.Views;

namespace QSHC.QSchedule.Silverlight.ViewModels
{
    public class BookingAppointmentViewModel : ViewModelBase
    {
        private QScheduleDomainContext _dc = new QScheduleDomainContext();

        #region Properties

        #region Property SelectedPatient
        private MedtrakPatientData _selectedPatient;
        public MedtrakPatientData SelectedPatient
        {
            get { return _selectedPatient; }
            set
            {
                if (_selectedPatient != value)
                {
                    _selectedPatient = value;
                    OnPropertyChanged(() => SelectedPatient);
                    OnPropertyChanged(() => PatientDetail);

                    AddCommand.OnCanExecuteChanged();
                }
            }
        }
        #endregion

        #region Property SelectedPatientHN
        private string _selectedPatientHN;
        public string SelectedPatientHN
        {
            get { return _selectedPatientHN; }
            set
            {
                if (_selectedPatientHN != value)
                {
                    _selectedPatientHN = value;
                    OnPropertyChanged(() => SelectedPatientHN);
                }
            }
        }
        #endregion

        #region Property PatientDetail
        public string PatientDetail
        {
            get
            {
                if (SelectedPatient == null)
                    return "ไม่พบผู้ป่วย HN นี้";

                string age = "-";

                if (SelectedPatient.BirthDate != null)
                {
                    age = SelectedPatient.BirthDate.Value.DateDiff().SetPrecision(DateDiffPrecision.Age).ToString();
                }

                var patientDetail = string.Format("{0}{1} {2} อายุ {3} ปี  อ.{4}  จ.{5}", 
                                        SelectedPatient.Title, SelectedPatient.FirstName, SelectedPatient.LastName,
                                        age, SelectedPatient.AmphurName, SelectedPatient.ProvinceName);

                return patientDetail;
            }
        }
        #endregion

        #region Property Services
        private IEnumerable<Service> _services;
        public IEnumerable<Service> Services
        {
            get { return _services; }
            set
            {
                if (_services != value)
                {
                    _services = value;
                    OnPropertyChanged(() => Services);
                }
            }
        }
        #endregion

        #region Property SelectedService
        private Service _selectedService;
        public Service SelectedService
        {
            get { return _selectedService; }
            set
            {
                if (_selectedService != value)
                {
                    _selectedService = value;
                    OnPropertyChanged(() => SelectedService);

                    GetPhysiciansInLocation();
                    AddCommand.OnCanExecuteChanged();
                    SearchCommand.OnCanExecuteChanged();

                    if (SelectedService != null)
                        AppointmentTime = SelectedService.DefaultAppointmentTime;
                }
            }
        }
        #endregion

        #region Property Physicians
        private IEnumerable<Employee> _physicians;
        public IEnumerable<Employee> Physicians
        {
            get { return _physicians; }
            set
            {
                if (_physicians != value)
                {
                    _physicians = value;
                    OnPropertyChanged(() => Physicians);
                }
            }
        }
        #endregion

        #region Property SelectedPhysician
        private Employee _selectedPhysician;
        public Employee SelectedPhysician
        {
            get { return _selectedPhysician; }
            set
            {
                if (_selectedPhysician != value)
                {
                    _selectedPhysician = value;
                    OnPropertyChanged(() => SelectedPhysician);

                    AddCommand.OnCanExecuteChanged();
                    SearchCommand.OnCanExecuteChanged();
                }
            }
        }
        #endregion

        #region Property SelectedPhysicianText
        private string _selectedPhysicianText;
        public string SelectedPhysicianText
        {
            get { return _selectedPhysicianText; }
            set
            {
                if (_selectedPhysicianText != value)
                {
                    _selectedPhysicianText = value;
                    OnPropertyChanged(() => SelectedPhysicianText);
                }
            }
        }
        #endregion

        #region Property AppointmentTime
        private string _appointmentTime;
        public string AppointmentTime
        {
            get { return _appointmentTime; }
            set
            {
                if (_appointmentTime != value)
                {
                    _appointmentTime = value;
                    OnPropertyChanged(() => AppointmentTime);
                }
            }
        }
        #endregion

        #region Property SelectedDate
        private DateTime? _selectedDate;
        public DateTime? SelectedDate
        {
            get { return _selectedDate; }
            set
            {
                if (_selectedDate != value)
                {
                    _selectedDate = value;
                    OnPropertyChanged(() => SelectedDate);

                    if (SelectedDate != null)
                    {
                        GetCurrentDatePhysicianScheduleQuota(() =>
                        {
                            AddCommand.OnCanExecuteChanged();
                        });
                    }
                }
            }
        }
        #endregion

        #region Property PreOrders
        private PreOrderMapping _preOrders;
        public PreOrderMapping PreOrders
        {
            get { return _preOrders; }
            set
            {
                if (_preOrders != value)
                {
                    _preOrders = value;
                    OnPropertyChanged(() => PreOrders);
                }
            }
        }
        #endregion

        #region Property Remark
        private string _remark;
        public string Remark
        {
            get { return _remark; }
            set
            {
                if (_remark != value)
                {
                    _remark = value;
                    OnPropertyChanged(() => Remark);
                }
            }
        }
        #endregion

        #region Property SelectedDayIndex
        private int _selectedDayIndex;
        public int SelectedDayIndex
        {
            get { return _selectedDayIndex; }
            set
            {
                if (_selectedDayIndex != value)
                {
                    _selectedDayIndex = value;
                    OnPropertyChanged(() => SelectedDayIndex);
                }
            }
        }
        #endregion

        #region Property SelectedDurationIndex
        private int _selectedDurationIndex;
        public int SelectedDurationIndex
        {
            get { return _selectedDurationIndex; }
            set
            {
                if (_selectedDurationIndex != value)
                {
                    _selectedDurationIndex = value;
                    OnPropertyChanged(() => SelectedDurationIndex);
                }
            }
        }
        #endregion
        
        #region Property Quota
        private int _quota;
        public int Quota
        {
            get { return _quota; }
            set
            {
                if (_quota != value)
                {
                    _quota = value;
                    OnPropertyChanged(() => Quota);
                }
            }
        }
        #endregion

        #region Property AppointedNumber
        private int _appointedNumber;
        public int AppointedNumber
        {
            get { return _appointedNumber; }
            set
            {
                if (_appointedNumber != value)
                {
                    _appointedNumber = value;
                    OnPropertyChanged(() => AppointedNumber);
                }
            }
        }
        #endregion

        //Daeng
        #region Property SumWeek
        private string _sumWeek;
        public string SumWeek
        {
            get { return _sumWeek; }
            set
            {
                if (_sumWeek != value)
                {
                    _sumWeek = value;
                    OnPropertyChanged(() => SumWeek);
                }
            }
        }
        #endregion

        #endregion

        #region Commands

        #region AddCommand
        private ViewModelCommand _addCommand = null;
        public ViewModelCommand AddCommand
        {
            get
            {
                if (_addCommand == null)
                    _addCommand = new ViewModelCommand(p => Add(p), p => CanAdd);
                return _addCommand;
            }
        }

        private void Add(object obj)
        {
            AddAppointment();
        }

        public bool CanAdd
        {
            get
            {
                return SelectedPatient != null &&
                       SelectedPhysician != null &&
                       SelectedService != null &&
                       AppointedNumber < Quota &&
                       (SelectedDate != null ? (SelectedDate.Value > DateTime.Now) : false );
            }
        }
        #endregion

        #region SearchCommand
        private ViewModelCommand _searchCommand = null;
        public ViewModelCommand SearchCommand
        {
            get
            {
                if (_searchCommand == null)
                    _searchCommand = new ViewModelCommand(p => Search(p), p => CanSearch);
                return _searchCommand;
            }
        }

        private void Search(object obj)
        {
            // TODO:
        }

        public bool CanSearch
        {
            get { return SelectedService != null && SelectedPhysician != null; }
        }
        #endregion

        #endregion

        public BookingAppointmentViewModel()
        {
            if (!IsInDesignModeStatic)
            {
                //Daeng UnComment
                #region Daeng UnComment
                CalendarHelper.LoadHolidaysAndSchedules(); // ART

                var loadBatch = new DomainContextLoadBatch(p =>
                {
                    Services = _dc.Services;
                });

                loadBatch.Add(_dc.Load(_dc.GetPhysicianSchedulesQuery()));
                loadBatch.Add(_dc.Load(_dc.GetPreOrdersQuery()));
                loadBatch.Add(_dc.Load(_dc.GetServicesQuery()));

                Reset();
                #endregion
            }
        }

        private void Reset()
        {
            SelectedPatient = null;
            SelectedPatientHN = string.Empty;
            SelectedService = null;
            SelectedPhysician = null;
            SelectedDate = null;
            PreOrders = new PreOrderMapping { Type_FollowUp = true };
            SelectedDayIndex = 0; // 1
            SelectedDurationIndex = 1; // สัปดาห์
        }

        private void GetPhysiciansInLocation()
        {
            SelectedPhysicianText = string.Empty;
            Physicians = _dc.PhysicianSchedules.Where(p => p.Service == SelectedService)
                                               .Select(p => EmployeeHelper.GetPhysician(p.Physician))
                                               .Distinct().OrderBy(p => p.FirstName);
        }

        private void AddAppointment()
        {
            var preOrders = PreOrders.GetPreOrders();

            if (preOrders.Count() == 0)
            {
                MessageBox.Show("คุณต้องเลือกคำสั่งล่วงหน้าอย่างน้อยหนึ่งรายการ");
                return;
            }

            var appointment = new Appointment
            {
                HN = SelectedPatient.HN,
                AppointmentDate = SelectedDate.Value,
                AppointmentTime = AppointmentTime,
                Service = SelectedService,
                Physician = SelectedPhysician.EmployeeCode,
                VisitDate = null,
                Remark = string.IsNullOrWhiteSpace(Remark) ? null : Remark,
            };

            foreach (var item in preOrders)
            {
                var apppointmentDetail = new AppointmentDetail
                {
                    PreOrder = _dc.PreOrders.Single(p => p.PreOrderID == item)
                };
                appointment.AppointmentDetails.Add(apppointmentDetail);
            }
            
            var log = new LogAppointment
            {
                EmployeeCode = EmployeeHelper.LoggedEmployee,
                LogDateTime = DateTime.Now,
                Action = 1, // Add
                Appointment = appointment,
            };

            var lo = _dc.Load(_dc.GetAppointedPatientsByHNQuery(SelectedPatient.HN));
            lo.Completed += (s, e) =>
            {
                var appointedPatient = lo.Entities.SingleOrDefault();

                // ART
                if (appointedPatient == null)
                {
                    appointedPatient = new AppointedPatient
                    {
                        HN = SelectedPatient.HN,
                        Title = SelectedPatient.Title,
                        FirstName = SelectedPatient.FirstName,
                        LastName = SelectedPatient.LastName,
                        Sex = SelectedPatient.Sex == null ? 0 : SelectedPatient.Sex.Value,
                        BirthDate = SelectedPatient.BirthDate,
                        PIN = SelectedPatient.PID,
                        Payor = SelectedPatient.PaymentName,
                        Address = SelectedPatient.Address,
                        Tambon = SelectedPatient.TambonName,
                        Amphur = SelectedPatient.AmphurName,
                        Province = SelectedPatient.ProvinceName,
                        //Phone = SelectedPatient.Pho
                    };
                    _dc.AppointedPatients.Add(appointedPatient);
                }
                else
                {
                    if (appointedPatient.Title != SelectedPatient.Title)
                    {
                        appointedPatient.Title = SelectedPatient.Title;
                    }
                    if (appointedPatient.FirstName != SelectedPatient.FirstName)
                    {
                        appointedPatient.FirstName = SelectedPatient.FirstName;
                    }
                    if (appointedPatient.LastName != SelectedPatient.LastName)
                    {
                        appointedPatient.LastName = SelectedPatient.LastName;
                    }
                    if (appointedPatient.Sex != (SelectedPatient.Sex == null ? 0 : SelectedPatient.Sex.Value))
                    {
                        appointedPatient.Sex = SelectedPatient.Sex == null ? 0 : SelectedPatient.Sex.Value;
                    }
                    if (appointedPatient.BirthDate != SelectedPatient.BirthDate)
                    {
                        appointedPatient.BirthDate = SelectedPatient.BirthDate;
                    }
                    if (appointedPatient.PIN != SelectedPatient.PID)
                    {
                        appointedPatient.PIN = SelectedPatient.PID;
                    }
                    if (appointedPatient.Payor != SelectedPatient.PaymentName)
                    {
                        appointedPatient.Payor = SelectedPatient.PaymentName;
                    }
                    if (appointedPatient.Address != SelectedPatient.Address)
                    {
                        appointedPatient.Address = SelectedPatient.Address;
                    }
                    if (appointedPatient.Tambon != SelectedPatient.TambonName)
                    {
                        appointedPatient.Tambon = SelectedPatient.TambonName;
                    }
                    if (appointedPatient.Amphur != SelectedPatient.AmphurName)
                    {
                        appointedPatient.Amphur = SelectedPatient.AmphurName;
                    }
                    if (appointedPatient.Province != SelectedPatient.ProvinceName)
                    {
                        appointedPatient.Province = SelectedPatient.ProvinceName;
                    }
                }

                _dc.Appointments.Add(appointment);
                _dc.SubmitChanges().Completed += (s2, e2) =>
                {
                    Reset();

                    var vm = new AppointmentCardViewModel(appointment);
                    var window = new AppointmentCardWindow();
                    window.DataContext = vm;
                    window.Show();
                };
            };
        }

        private void GetCurrentDatePhysicianScheduleQuota(Action callback)
        {
            var countDate = SelectedDate.Value.Date - DateTime.Now.Date;
            if (countDate != null)
            {
                SumWeek = string.Format("{0} สัปดาห์ {1} วัน", (countDate.Days / 7), (countDate.Days % 7));
            }

            if (SelectedService.ServiceID == 6) //คลีนิคนอกเวลา
            {
                if (SelectedDate != null)
                {
                    switch (SelectedDate.Value.DayOfWeek)
                    {
                        case DayOfWeek.Saturday:
                            AppointmentTime = "8.00";
                            break;
                        case DayOfWeek.Sunday:
                            AppointmentTime = "8.00";
                            break;
                        default:
                            AppointmentTime = "16.00";
                            break;
                    }
                }
            }

            var a = _dc.PhysicianSchedules.Where(p => p.Service == SelectedService &&
                                                      p.Physician == SelectedPhysician.EmployeeCode &&
                                                      p.DayOfWeek == (int)SelectedDate.Value.DayOfWeek).Where(p => p.EndDate != null ? (p.BeginDate <= SelectedDate && p.EndDate >= SelectedDate) :
                                                      (SelectedDate >= p.BeginDate));
            //Daeng
            int quota = 0;
            foreach (var item in a)
                quota = quota + item.Quota;

            Quota = quota;

            var qry = from p in _dc.GetAppointmentsQuery()
                      where p.AppointmentDate == SelectedDate &&
                            p.ServiceID == SelectedService.ServiceID &&
                            p.Physician == SelectedPhysician.EmployeeCode
                      select p;

            var lo = _dc.Load(qry);
            lo.Completed += (s,e) =>
            {
                AppointedNumber = lo.Entities.Where(p => !p.AppointmentDetails.Any(o => o.PreOrderID == 16 || o.PreOrderID == 32)) // ART 16=นัดรับยา Daeng 32=นัดติดตามหลังผ่าตัด
                                             .Count();

                callback.Invoke();
            };
        }

        private bool ValidatePreOrders()
        {
            return true;
        }
    }
}
